package com.nbstar.film.spider.spider;

import com.nbstar.film.spider.filter.*;
import com.nbstar.film.spider.font.woff.WoffFont;
import com.nbstar.film.spider.font.woff.WoffParse;
import com.nbstar.film.spider.font.woff.table.CmapTable;
import com.nbstar.film.spider.font.woff.table.glyf.GlyphData;
import com.nbstar.film.spider.font.woff.table.glyf.GlyphTable;
import com.nbstar.film.spider.http.*;
import com.nbstar.film.spider.pojo.FilmInfo;
import com.nbstar.film.spider.pojo.MaoYanFilmInfo;


import com.nbstar.film.spider.filter.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.*;
import org.openqa.selenium.Point;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Data
public class MaoYanSpider extends BaseSpider {
    //private static Logger logger = LoggerFactory.getLogger(MaoYanSpider.class);
    private static final int width = 500;
    private static final int height = 850;
    private static final String dir = "E:\\运营开发";



    public MaoYanSpider() {
        setRequest(new SipderStringRequest());
        this.spiderName = "MAOYAN";
        getRequest().setProtol("https");
        getRequest().clearHeader();
        getRequest().addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
        getRequest().addHeader("Accept-Encoding", "gzip, deflate, br");
        getRequest().addHeader("Accept-Language", "zh-CN,zh;q=0.9");
        getRequest().addHeader("Referer", "https://maoyan.com/films");
        getRequest().addHeader("User-Agent", getRequest().randomAgent());
        getRequest().addHeader("Cookie", "__mta=146701963.1595397593195.1595513670316.1595513683902.11; uuid_n_v=v1; uuid=9040A550CBE011EA8AF6570E3933DABA347DE2E369714B6D858ECA4B1B1BA9DF; _lxsdk_cuid=173751b567fc8-0af0b5c23f997c-3e385e0c-100200-173751b5680c8; _lxsdk=9040A550CBE011EA8AF6570E3933DABA347DE2E369714B6D858ECA4B1B1BA9DF; mojo-uuid=e4f4ee89e9b52161439f705011c22527; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _csrf=226c6c1a19484272c7d2fcfd476751bfe1aad1f603f4db18a4a738248327fd2c; mojo-session-id={\"id\":\"5bb3999c6d1f74e6a6b9aa8032317dce\",\"time\":1595513480165}; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1595397593,1595479537,1595492691,1595513480; __mta=146701963.1595397593195.1595494232103.1595513480656.7; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1595513684; mojo-trace-id=5; _lxsdk_s=1737c03a4ba-6cc-87-e89%7C%7C6");

        registFilter(new ReplaceBracketsNameFilter());
        registFilter(new ReplaceCHColonNameFilter());
        registFilter(new ReplaceChCommaNameFilter());
        registFilter(new ReplaceCHDotNameFilter());
        registFilter(new ReplaceColonNameFilter());
        registFilter(new ReplaceCommaNameFilter());
        registFilter(new ReplaceCHQuotesNameFilter());
        registFilter(new ReplaceQuotesNameFilter());
    }

    @Override
    public String getContentId(String filmName) throws Exception {
        String url = "https://maoyan.com/query?kw=" + java.net.URLEncoder.encode(filmName,"utf-8");
        String html  = getRequest().getHtml(url);
        try {
            if (html.contains("您的访问请求由于过于频繁而被禁止")) {

                html  = firefoxDriverRequest.getHtml(url);;
            }

            if (html.contains("验证中心")) {

                html = firefoxDriverRequest.getHtml(url);

                while (html.contains("验证中心")) {
                    log.debug("{}getContentId需要滑动验证....", filmName);
                    verify(firefoxDriverRequest.getDriver());
                    Thread.sleep(3000);
                    html = firefoxDriverRequest.getHtml(url);
                }
            }


            Document doc = Jsoup.parse(html);

            Elements filmChanel = doc.getElementsByClass("channel-detail movie-item-title");
            Elements links = filmChanel.select("a[href]");
            for (Element link : links) {
                String href = link.attr("href");
                String name = link.text();
                System.out.println(href + ":" + name);

                String webName = parseName(name);
                //if (name.trim().replace(" ", "").equals(filmName.replace(" ", ""))) {
                if (webName.equals(filmName)) {
                    return "https://maoyan.com" + href;
                }

            }
        } catch (Exception e) {
            throw e;
        }


        return  "";
    }

    private  void saveFile(GeneralPath path, String filename) throws IOException {
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
        graphics2D.setColor(Color.white);
        graphics2D.fillRect(0, 0, width, height);
        graphics2D.setColor(Color.BLACK);
        graphics2D.translate(600, 300);
        double[] matrix = new double[] { 1, 0, 0, -1, 0, height - 100};
        AffineTransform affineTransform = new AffineTransform(matrix);
        graphics2D.setTransform(affineTransform);
        graphics2D.fill(path);

        ImageIO.write(bufferedImage, "jpg", new File(dir + "/" + filename));

    }

    public static String getUnicode(Map<Integer, Integer> cmap, int i) {
        for (Map.Entry<Integer, Integer> entry : cmap.entrySet()){
            if (entry.getValue() == i) {
                return Integer.toHexString(entry.getKey()).toUpperCase();
            }
        }
        return "null";
    }

    public Map<String, Integer> parseWoff(InputStream inputStream) {
        WoffParse parse = new WoffParse();
        Map<String, Integer> ret = new HashMap<String, Integer>();

        try {
            WoffFont font = parse.parse(inputStream);
            CmapTable cmap = font.getCmap();
            Map<Integer, Integer> characterCodeToGlyphId = cmap.getWindowCharacterCodeToGlyphId();
            System.out.println("font:" + font);
            System.out.println(cmap.toString());
            GlyphTable glyphTable = font.getGlyph();
            GlyphData[] glyphDatas = glyphTable.getGlyphs();
            for (int i = 0; i < glyphDatas.length; i++) {
                GlyphData gd = glyphDatas[i];
                if (null == gd) {
                    continue;
                }
                System.out.println();
                //if (i == 3) {
                {
                    GeneralPath path = gd.getPath();
                    String filename = UUID.randomUUID().toString() + ".jpg";
                    saveFile(path, filename);
                    File imageFile = new File(dir + "/"  + filename);
                    Tesseract instance = new Tesseract();  // JNA Interface Mapping
                    instance.setDatapath("E:\\tessdata-ocr");
                    //instance.setLanguage("osd");
                    instance.setLanguage("dan_frak");

                    try {
                        String result = instance.doOCR(imageFile).trim();
                        //byte[] data = result.getBytes();
                        //System.out.println("uni" + getUnicode(characterCodeToGlyphId, i) + ":" + result);
                        int val = -1;
                        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
                        if (pattern.matcher(result).matches()) {
                            val = Integer.parseInt(result);
                        }

                        ret.put("uni" + getUnicode(characterCodeToGlyphId, i), val);

                    } catch (TesseractException e) {
                        e.printStackTrace();
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                    } finally {

                        imageFile.delete();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    private String transStoneFont(Map<String, Integer> woffTable, String stonefont) {
        String score = "";
        for (int i=0; i<stonefont.length(); i++) {

            String key = "uni" + Integer.toHexString(stonefont.charAt(i)).toUpperCase();
            //System.out.println(key );
            if (key.equals("uni2E")) {
                score += ".";
            } else {
                score += woffTable.get(key);
            }
        }

        return score;
    }

    public synchronized   void verify(WebDriver driver) throws InterruptedException {
        WebDriverWait wait = new WebDriverWait(driver, 10);
        WebElement yodaBox = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("yodaBox")));
        //WebElement moveingBar  = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("moveingBar")));
        WebElement moveingBar  = driver.findElement(By.id("yodaMoveingBar"));

        //System.out.println(((ChromeDriver) driver).executeScript("return document.body.clientWidth"));
        //System.out.println(((ChromeDriver) driver).executeScript("return document.getElementById('yodaBox').getBoundingClientRect().left"));
        //System.out.println(((ChromeDriver) driver).executeScript("return document.getElementById('yodaBox').getBoundingClientRect().top"));

        org.openqa.selenium.Point location = yodaBox.getLocation();
        org.openqa.selenium.Dimension boxSize = yodaBox.getSize();
        org.openqa.selenium.Dimension barSize = moveingBar.getSize();
        Actions action = new Actions(driver);
        Thread.sleep(8000);

        org.openqa.selenium.Point[] trace = new org.openqa.selenium.Point[]{};

        int distance = boxSize.width + barSize.width;

        Random random = new Random();
        int s = random.nextInt(10) + 3;

        int step = distance / s;

        if (distance % s != 0 ) {
            s -= 1;
        }
        action.clickAndHold(yodaBox).perform();
        action.moveByOffset(location.x+boxSize.width + barSize.width, location.y+9);
        action.release().perform();
       // action.dragAndDropBy(yodaBox, location.x+boxSize.width + barSize.width,location.y+9).perform();

        System.out.println("滑动：" +  boxSize + ":" + new Point(location.x+boxSize.width + barSize.width + 10,location.y+9));

    }

    @Override
    public FilmInfo getFilmInfo(String url) throws Exception {
        MaoYanFilmInfo filmInfo = new MaoYanFilmInfo();
        //String result  = HttpRequest.maoYanGetFilmInfo(url);

        if (StringUtils.isEmpty(url)) {
            return filmInfo;
        }

        String result  = getRequest().getHtml(url);

        try {
            if (result.contains("您的访问请求由于过于频繁而被禁止")) {
                //firefoxDriverRequest.setProxy(firefoxDriverRequest.getDefaultProxy());
                //firefoxDriverRequest.init(true);
                result  = firefoxDriverRequest.getHtml(url);;

                //firefoxDriverRequest.close();;
            }

            if (result.contains("验证中心")) {
                 //firefoxDriverRequest = new FirefoxDriverRequest();
//                Proxy proxy = new Proxy();
//                proxy.setHttpProxy(getRequest().getProxyInfo().getProxy().replace("http://", ""));
//                proxy.setSslProxy(getRequest().getProxyInfo().getProxy().replace("http://", ""));
//                firefoxDriverRequest.setProxy(proxy);
                //firefoxDriverRequest.setProxy(firefoxDriverRequest.getDefaultProxy());
                //firefoxDriverRequest.init(true);
                System.out.println("getFilmInfo需要滑动验证....");

                result = firefoxDriverRequest.getHtml(url);
                while (result.contains("验证中心")) {

                    verify(firefoxDriverRequest.getDriver());
                    Thread.sleep(3000);
                    //firefoxDriverRequest.close();
                    //firefoxDriverRequest.init(true);
                    result = firefoxDriverRequest.getHtml(url);
                }

                //firefoxDriverRequest.close();

            }

            Document doc = Jsoup.parse(result);
            Pattern pattern = Pattern.compile("vfile.*.woff" );
            Matcher matcher = pattern.matcher(result);
            String fontURL = "";
            // 创建 Pattern 对象
            if (matcher.find()) {
                fontURL = matcher.group(0).replace("') format('woff", "");
                log.info("font requet:" + fontURL);
            }

            byte[] woff = new SipderBinRequest().getBin("https://" + fontURL);

            Map<String, Integer> woffTable = parseWoff( new ByteArrayInputStream(woff));

            Elements info_num = doc.getElementsByClass("index-left info-num ");
            if (info_num.size() == 0) {
                info_num = doc.getElementsByClass("index-left info-num one-line");
            }

            if (info_num.size() > 0) {
                Elements stonefonts1 = info_num.get(0).getElementsByClass("stonefont");
                //FileUtils f;

                String score = transStoneFont(woffTable, stonefonts1.get(0).text());

                //logger.info("猫眼score:" + score);
                filmInfo.setAverage(Double.parseDouble(score));
            }

            //获取票房

            Elements boxoffice = doc.getElementsByClass("movie-index-content box");
            //System.out.println(boxoffice);

            if (boxoffice.size() > 0) {
                String boxoffNum = transStoneFont(woffTable, boxoffice.select(".stonefont").text());
                //String boxoffUnit = boxoffice.select(".unit").text();

                String unit = boxoffice.text().trim();
                if (unit.contains("万")) {
                    double boxNum = Double.parseDouble(boxoffNum);
                    boxNum /= 10000;
                    filmInfo.setBoxOffice(boxNum + "");
                } else {
                    //boxoffNum = transStoneFont(woffTable, boxoffNum);
                    filmInfo.setBoxOffice(boxoffNum);
                }
            }

            Elements score_num = doc.getElementsByClass("score-num");
            if (score_num.size() > 0) {
                Elements stonefonts2 = score_num.get(0).getElementsByClass("stonefont");


                String votes = "";
                String unit = null;
                for (int i = 0; i < stonefonts2.get(0).text().length(); i++) {

                    if (stonefonts2.get(0).text().charAt(i) == '万') {
                        unit = "万";
                    } else {
                        String key = "uni" + Integer.toHexString(stonefonts2.get(0).text().charAt(i)).toUpperCase();
                        System.out.println(key);
                        if (key.equals("uni2E")) {
                            votes += ".";
                        } else {
                            votes += woffTable.get(key);
                        }
                    }
                }


                log.info("猫眼评论人数:" + votes);


                double v = Double.parseDouble(votes);
                if (unit == "万") {
                    v = v * 10000;
                }

                filmInfo.setVotes((long) v);
            }

            //简介
            Elements dra = doc.getElementsByClass("dra");
            if (dra != null) {
                filmInfo.setDesc(dra.text().trim());
            }

            //导演及演员
            Elements celebrity = doc.getElementsByClass("celebrity");
            if (celebrity != null) {
                String[] workers = celebrity.text().replace("：", " ").replace(" ", ";").split(";");
                if (workers.length > 1) {
                    filmInfo.setDirector(workers[0]);
                    String actor = "";
                    for (int i=1; i<workers.length; i++) {
                        if (workers[i].equals("饰")) {
                            actor += workers[i-1] + " ";
                        }
                    }
                    filmInfo.setActor(actor);
                }

            }


            Elements container = doc.getElementsByClass("movie-brief-container");
            if (container.size() > 0) {
                Elements ename = container.get(0).getElementsByClass("ename ellipsis");
                filmInfo.setEname(ename.get(0).text().trim());


                Elements ellipsis = container.get(0).getElementsByClass("ellipsis");
                Elements links = ellipsis.select("a[href]");
                if (links != null) {
                    filmInfo.setCategory(links.text().trim());
                }

                String REGEX_CHINESE = "[\u4e00-\u9fa5]";// 中文正则

                Pattern pat = Pattern.compile(REGEX_CHINESE);
                if (ellipsis.size() >= 4) {
                    String dd = ellipsis.get(3).text();
                    Matcher mat = pat.matcher(dd);
                    filmInfo.setArriveDate(mat.replaceAll(""));
                }


                for (Element e : ellipsis) {
                    if (e.text().contains("/")) {
                        String[] infos = e.text().split("/");
                        filmInfo.setArriveAddress(infos[0].trim());
                        filmInfo.setFileDuration(infos[1].trim());
                    }

                    System.out.println(e.text());
                }
            }

        } catch (Exception e) {
            throw e;
        }

        filmInfo.setSuccess(true);
        return filmInfo;
    }


}
